﻿/*
** Xin YUAN, 2021, BSD (2)
*/

////////////////////////////////////////////////////////////////////////////////
#ifndef __CTL_TRAITS_H__
#define __CTL_TRAITS_H__
////////////////////////////////////////////////////////////////////////////////

#include "cslmem.h"

// Basic Types

/*
=== in stdint.h ===
int8_t
uint8_t
int16_t
uint16_t
int32_t
uint32_t
int64_t
uint64_t
intptr_t
uintptr_t
=== in cslbase.h ===
char_s
=== C/C++ ===
char
*/

// Macros

/*
=== C/C++ ===
assert
=== cslbase.h ===
_s
*/

// Functions

template <typename T>
inline T&& rv_forward(T& t) noexcept
{
	return std::forward<T>(t);
}

template <typename T, typename... Args>
inline void call_constructor(T& t, Args&&... args)
{
	CSL::call_constructor(t, std::forward<Args>(args)...);  //may throw
}

template <typename T>
inline void call_destructor(T& t) noexcept
{
	CSL::call_destructor(t);
}

inline void thread_sleep(uint32_t tm) noexcept
{
	std::this_thread::sleep_for(std::chrono::milliseconds(tm));
}

////////////////////////////////////////////////////////////////////////////////
namespace CTL {
////////////////////////////////////////////////////////////////////////////////

// Operators

template <typename T>
class NumericTraits
{
public:
	static constexpr const T MinValue = (std::numeric_limits<T>::min)();
	static constexpr const T MaxValue = (std::numeric_limits<T>::max)();
};

template <typename T>
class ArithmeticTraits
{
public:
	static bool Add(T t1, T t2, T& r) noexcept
	{
		return CSL::SafeOperators::Add(t1, t2, r);
	}
	static bool Multiply(T t1, T t2, T& r) noexcept
	{
		return CSL::SafeOperators::Multiply(t1, t2, r);
	}
	static T AddThrow(T t1, T t2)
	{
		return CSL::SafeOperators::AddThrow(t1, t2);  //may throw
	}
	static T MultiplyThrow(T t1, T t2)
	{
		return CSL::SafeOperators::MultiplyThrow(t1, t2);  //may throw
	}
};

template <typename T>
class NumberTraits
{
public:
	static T Abs(T t) noexcept
	{
		return std::abs(t);
	}
	static bool IsOdd(T t) noexcept
	{
		return (t & (T)1) != 0;
	}
};

template <typename T>
class FloatTraits
{
public:
	static bool isfinite(T t) noexcept
	{
		return std::isfinite(t);
	}
	static T acos(T t) noexcept
	{
		return std::acos(t);
	}
	static T acosh(T t) noexcept
	{
		return std::acosh(t);
	}
	static T asin(T t) noexcept
	{
		return std::asin(t);
	}
	static T asinh(T t) noexcept
	{
		return std::asinh(t);
	}
	static T atan2(T t1, T t2) noexcept
	{
		return std::atan2(t1, t2);
	}
	static T atanh(T t) noexcept
	{
		return std::atanh(t);
	}
	static T cos(T t) noexcept
	{
		return std::cos(t);
	}
	static T cosh(T t) noexcept
	{
		return std::cosh(t);
	}
	static T exp(T t) noexcept
	{
		return std::exp(t);
	}
	static T ldexp(T t, int e) noexcept
	{
		return std::ldexp(t, e);
	}
	static T log(T t) noexcept
	{
		return std::log(t);
	}
	static T log10(T t) noexcept
	{
		return std::log10(t);
	}
	static T log2(T t) noexcept
	{
		return std::log2(t);
	}
	static T pow(T t1, T t2) noexcept
	{
		return std::pow(t1, t2);
	}
	static T sin(T t) noexcept
	{
		return std::sin(t);
	}
	static T sinh(T t) noexcept
	{
		return std::sinh(t);
	}
	static T sqrt(T t) noexcept
	{
		return std::sqrt(t);
	}
	static T tan(T t) noexcept
	{
		return std::tan(t);
	}
	static T tanh(T t) noexcept
	{
		return std::tanh(t);
	}
	static T ceil(T t) noexcept
	{
		return std::ceil(t);
	}
	static T floor(T t) noexcept
	{
		return std::floor(t);
	}
	static T round(T t) noexcept
	{
		return std::round(t);
	}
	static T trunc(T t) noexcept
	{
		return std::trunc(t);
	}
};

template <typename T>
using DefaultCompareTrait = CSL::DefaultCompareTrait<T>;

template <class TTrait>
class CompareTraits
{
public:
	typedef typename TTrait::value_type  ValueType;
	typedef TTrait  TraitType;

	static bool EQ(const ValueType& t1, const ValueType& t2) noexcept
	{
		return TraitType::IsEQ(t1, t2);
	}
	static bool NE(const ValueType& t1, const ValueType& t2) noexcept
	{
		return TraitType::IsNE(t1, t2);
	}
	static bool LT(const ValueType& t1, const ValueType& t2) noexcept
	{
		return TraitType::IsLT(t1, t2);
	}
	static bool LE(const ValueType& t1, const ValueType& t2) noexcept
	{
		return TraitType::IsLE(t1, t2);
	}
	static bool GT(const ValueType& t1, const ValueType& t2) noexcept
	{
		return TraitType::IsGT(t1, t2);
	}
	static bool GE(const ValueType& t1, const ValueType& t2) noexcept
	{
		return TraitType::IsGE(t1, t2);
	}
	static int32_t Compare(const ValueType& t1, const ValueType& t2) noexcept
	{
		return TraitType::Compare(t1, t2);
	}
};

// Byte Order

class ByteOrderTraits
{
public:
	static bool IsBigEndianHost() noexcept
	{
		return CSL::ByteOrderHelper::IsBigEndianHost();
	}
	template <typename T>
	static T Swap(T x) noexcept
	{
		return CSL::ByteOrderHelper::Swap(x);
	}
};

// Memory

class MemoryTraits
{
public:
	static void Copy(const void* src, uintptr_t size, void* dest) noexcept
	{
		::memcpy(dest, src, size);
	}
	static void Move(const void* src, uintptr_t size, void* dest) noexcept
	{
		::memmove(dest, src, size);
	}
	static void Zero(void* dest, uintptr_t size) noexcept
	{
		::memset(dest, 0, size);
	}
	static void Fill(uint8_t value, void* dest, uintptr_t size) noexcept
	{
		::memset(dest, value, size);
	}
};

// Exceptions

class ExceptionTraits
{
public:
	static void ThrowInvalid()
	{
		throw std::invalid_argument("");  //throw
	}
	static void ThrowMemory()
	{
		throw std::bad_alloc();  //throw
	}
	static void ThrowOverflow()
	{
		throw std::overflow_error("");  //throw
	}
	static void ThrowUnexpected()
	{
		throw std::runtime_error("");  //throw
	}
};

// Containers

template <class TIterator>
class IteratorTraits
{
public:
	typedef typename TIterator::value_type  ValueType;
	typedef TIterator  IteratorType;

	static intptr_t CalcDistance(const IteratorType& begin, const IteratorType& end) noexcept
	{
		return std::distance(begin, end);
	}
	static const ValueType& Get(const IteratorType& it) noexcept
	{
		return *it;
	}
	static ValueType& Get(IteratorType& it) noexcept
	{
		return *it;
	}
	static IteratorType Move(const IteratorType& it, intptr_t delta) noexcept
	{
		return it + delta;
	}
	static void Move(intptr_t delta, IteratorType& it) noexcept
	{
		it += delta;
	}
	static void ToNext(IteratorType& it) noexcept
	{
		++ it;
	}
	static void ToPrev(IteratorType& it) noexcept
	{
		-- it;
	}
	template <class TFunctor>
	static void ForEach(const IteratorType& itb, const IteratorType& ite, const TFunctor& func)
	{
		std::for_each(itb, ite, func);
	}
};

template <typename T>
class ArrayTraits
{
public:
	typedef T  ValueType;
	typedef std::vector<T>  ArrayType;

	static uintptr_t GetSize(const ArrayType& arr) noexcept
	{
		return arr.size();
	}
	static const ValueType* GetAddress(const ArrayType& arr) noexcept
	{
		return &arr.front();
	}
	static ValueType* GetAddress(ArrayType& arr) noexcept
	{
		return &arr.front();
	}
	static const ValueType& GetAt(const ArrayType& arr, uintptr_t index) noexcept
	{
		return arr[index];
	}
	static ValueType& GetAt(ArrayType& arr, uintptr_t index) noexcept
	{
		return arr[index];
	}
	static void Clear(ArrayType& arr) noexcept
	{
		arr.clear();
	}
	static void SetSize(ArrayType& arr, uintptr_t size)
	{
		arr.resize(size);  //may throw
	}
	static void Append(const ValueType& src, ArrayType& arr)
	{
		arr.push_back(src);  //may throw
	}
	static void RemoveAt(ArrayType& arr, uintptr_t index) noexcept
	{
		arr.erase(arr.begin() + index);
	}
	template <typename... Args>
	static void InsertAt(ArrayType& arr, uintptr_t index, Args&&... args)
	{
		arr.emplace(arr.begin() + index, rv_forward<Args>(args)...);
	}
};

template <typename Tchar>
class CharTraits
{
public:
	typedef Tchar  CharType;

	static CharType ToLower(CharType ch) noexcept
	{
		return CSL::CharHelper::ToLower(ch);
	}
	static CharType ToUpper(CharType ch) noexcept
	{
		return CSL::CharHelper::ToUpper(ch);
	}
	static bool IsAlnum(CharType ch) noexcept
	{
		return CSL::CharHelper::IsAlnum(ch);
	}
	static bool IsAlpha(CharType ch) noexcept
	{
		return CSL::CharHelper::IsAlpha(ch);
	}
	static bool IsCntrl(CharType ch) noexcept
	{
		return CSL::CharHelper::IsCntrl(ch);
	}
	static bool IsGraph(CharType ch) noexcept
	{
		return CSL::CharHelper::IsGraph(ch);
	}
	static bool IsLower(CharType ch) noexcept
	{
		return CSL::CharHelper::IsLower(ch);
	}
	static bool IsUpper(CharType ch) noexcept
	{
		return CSL::CharHelper::IsUpper(ch);
	}
	static bool IsDigit(CharType ch) noexcept
	{
		return CSL::CharHelper::IsDigit(ch);
	}
	static bool IsXdigit(CharType ch) noexcept
	{
		return CSL::CharHelper::IsXdigit(ch);
	}
	static bool IsBlank(CharType ch) noexcept
	{
		return CSL::CharHelper::IsBlank(ch);
	}
	static bool IsSpace(CharType ch) noexcept
	{
		return CSL::CharHelper::IsSpace(ch);
	}
	static bool IsPrint(CharType ch) noexcept
	{
		return CSL::CharHelper::IsPrint(ch);
	}
	static bool IsPunct(CharType ch) noexcept
	{
		return CSL::CharHelper::IsPunct(ch);
	}
	static uintptr_t GetLength(const CharType* sz) noexcept
	{
		return CSL::StringHelper::CalcLength(sz);
	}
};

template <class TString>
class StringTraits
{
public:
	typedef typename TString::value_type  CharType;
	typedef TString  StringType;

	static uintptr_t GetLength(const StringType& str) noexcept
	{
		return str.size();
	}
	static const CharType* GetAddress(const StringType& str) noexcept
	{
		return &str.front();
	}
	static CharType* GetAddress(StringType& str) noexcept
	{
		return &str.front();
	}
	static void Clear(StringType& str) noexcept
	{
		str.clear();
	}
	static void Append(CharType ch, StringType& str)
	{
		str += ch;  //may throw
	}
	static void Append(const CharType* sz, StringType& str)
	{
		str += sz;  //may throw
	}
	static void Append(const StringType& src, StringType& str)
	{
		str += src;  //may throw
	}
};

////////////////////////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////
#endif
////////////////////////////////////////////////////////////////////////////////
